![Terraform 1.3がGAになりました](https://devio2023-media.developers.io/wp-content/uploads/2019/05/terraform-eyecatch.png)
Terraform 1.3がGAになりました
2022/09/22 にTerrafrom 1.3 がGA(generally available)になりました。新機能をチェックしていきましょう。
ObjectタイプのVariableに任意のattributesを設定可能に
Variableのtypeでobjectを指定した際の新機能です。
1.3以前でも、オブジェクトの必須attributeは設定することができました。
必須attributeの例
variable "hoge" { type = object({ a = string }) }
hoge = { b = "bbb" }
% terraform plan ╷ │ Error: Invalid value for input variable │ │ on terraform.tfvars line 1: │ 1: hoge = { │ 2: b = "bbb" │ 3: } │ │ The given value is not suitable for var.hoge declared at varables.tf:1,1-16: attribute "a" is required.
必須attributeを追加します。
hoge = { a = "aaa" b = "bbb" }
デバッグ用に以下のoutputも定義しておきます。
output "hoge_result" { value = var.hoge }
% terraform apply (略) Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: hoge_result = { "a" = "aaa" }
apply成功しました。かつ、variable定義で記載していなかった b attributeは削除されていますね。
任意のattribute例
1.3からoptional関数が追加されました。これが使用されたattributeは任意attributeになります。
variable "hoge" { type = object({ a = string + b = optional(string) }) }
hoge = { a = "aaa" }
% terraform apply (略) Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: hoge_result = { "a" = "aaa" "b" = tostring(null) }
optional attributeなbにはnullが入りましたね。
デフォルト値も設定できる
optional関数の第二引数にデフォルト値を設定できます。
variable "hoge" { type = object({ a = string - b = optional(string) + b = optional(string, "this is default value") }) }
% terraform apply (略) Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: hoge_result = { "a" = "aaa" "b" = "this is default value" }
ユースケース
いろんなパターンに対応したいようなモジュールでは活躍しそうな気がしますね。Terraform RegistryやGitHubに公開されているようなモジュールがこれに当てはまることが多いと思います。最近私は aws-ia/terraform-aws-eks-blueprints: 内のサブモジュールを利用することが多いのですが、これがまさしくobject型で配下に大量のattributesを持つ形式のvariables(例)が多く、必要ないattributesもとりあえず定義して渡す必要がありました。このあたりoptional関数を駆使してvariablesを定義してもらえるとより使いやすいモジュールになりそうです。
movedブロックのtoで外部moduleを指定可能に
Version 1.1で導入された moved blockが改良されました。
これまでの movedブロックは fromがローカルで定義したリソース(=ローカルのsub module内やroot module直下のリソース)の場合、toに外部module(Terraform RegistryやGitHub上になどあるmodule)を指定できませんでした。
# resource "aws_vpc" "main" { # cidr_block = "10.0.0.0/16" # tags = { # Name = "my-vpc" # } # } module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.14.4" name = "my-vpc" cidr = "10.0.0.0/16" } moved { from = aws_vpc.main to = module.vpc.aws_vpc.this[0] }
% terraform apply module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-0810dce1ba1a574d9] ╷ │ Error: Cross-package move statement │ │ on vpc.tf line 9: │ 9: moved { │ │ This statement declares a move to an object declared in external module package "registry.terraform.io/terraform-aws-modules/vpc/aws". Move statements can be only within a single module package. ╵
これが1.3では実行可能になりました。
% terraform apply module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-07cc8f31365d58b4b] Terraform will perform the following actions: # aws_vpc.main has moved to module.vpc.aws_vpc.this[0] resource "aws_vpc" "this" { id = "vpc-07cc8f31365d58b4b" tags = { "Name" = "my-vpc" } # (16 unchanged attributes hidden) } Plan: 0 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
地味なアップデートではありますが、できることが増えるのは嬉しいですね。
ちなみにこういうのは1.3以前からできます
逆 (external → ローカル)
# module "vpc" { # source = "terraform-aws-modules/vpc/aws" # version = "3.14.4" # name = "my-vpc" # cidr = "10.0.0.0/16" # } resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "my-vpc" } } moved { from = module.vpc.aws_vpc.this[0] to = aws_vpc.main }
external → external
# module "vpc" { module "vpc_rename" { source = "terraform-aws-modules/vpc/aws" version = "3.14.4" name = "my-vpc" cidr = "10.0.0.0/16" } moved { from = module.vpc to = module.vpc_rename }
startswith()
, endswith()
関数で文字列のprefix、suffixがチェック可能に
% terraform console > startswith("classmethod", "class") true > startswith("classmethod", "glass") false > endswith("classmethod", "method") true > endswith("classmethod", "meth") false
あまりユースケースを思いつけませんでしたが、セキュリティグループIDなどprefix(もしくはsuffix)が決まっているものをvariablesにする場合のvalidationに使うことができますね。
variable "sg_id" { type = string validation { condition = startswith(var.sg_id, "sg-") error_message = "Security Group ID must starts with 'sg-' " } }
一応1.3以前でも正規表現を使えば実装できますが、startswith(endswith)の方がわかりやすいですね。
variable "sg_id" { type = string validation { condition = length(regexall("^sg-", var.sg_id)) > 0 error_message = "Security Group ID must starts with 'sg-' " } }
参考情報
- Release v1.3.0 · hashicorp/terraform
- Terraform 1.3 Improves Extensibility and Maintainability of Terraform Modules
- Optional Object Type Attributes | Type Constraints - Configuration Language | Terraform | HashiCorp Developer
- startswith - Functions - Configuration Language | Terraform | HashiCorp Developer
- endswith - Functions - Configuration Language | Terraform | HashiCorp Developer